package com.samphanie.admin.modules.sys.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.samphanie.admin.modules.sys.domain.dto.LoginDto;
import com.samphanie.admin.modules.sys.domain.vo.Oauth2TokenVo;
import com.samphanie.admin.modules.sys.service.ISysRoleService;
import com.samphanie.admin.modules.sys.service.ISysUserService;
import com.samphanie.common.enums.OauthLoginType;
import com.samphanie.common.enums.ResultCode;
import com.samphanie.common.execetion.ApiException;
import com.samphanie.common.utils.ApiResponse;
import com.samphanie.common.utils.SpringEnvironmentUtils;
import com.samphanie.mbg.mapper.sys.SysUserMapper;
import com.samphanie.mbg.model.sys.SysRole;
import com.samphanie.mbg.model.sys.SysUser;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Optional;

/**
 * @author ZSY
 * @date 2021/11/9 10:04
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    private final PasswordEncoder passwordEncoder;
    private final ISysRoleService roleService;

    private final SpringEnvironmentUtils springEnvironmentUtils;
    private final RestTemplate restTemplate;

    /**
     * 用户名密码登录
     *
     * @param loginDto 登录表单
     * @return ApiResponse<?>
     */
    @Override
    public Oauth2TokenVo userLogin(LoginDto loginDto) {
        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/x-www-form-urlencoded");
        // 设置请求参数
        MultiValueMap<String, Object> paramsMap = new LinkedMultiValueMap<>();
        paramsMap.set("grant_type", OauthLoginType.PASSWORD.getType());
        paramsMap.set("client_id", loginDto.getClientId());
        paramsMap.set("client_secret", loginDto.getClientSecret());
        paramsMap.set("username", loginDto.getUsername());
        paramsMap.set("password", loginDto.getPassword());

        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(paramsMap, headers);
        ApiResponse<?> apiResponse = restTemplate.postForObject(springEnvironmentUtils.getLocalHostAddress() + "/oauth/token", httpEntity, ApiResponse.class);
        if (apiResponse != null) {
            if (!apiResponse.successful()) {
                throw new ApiException(apiResponse.getMessage());
            }
            // TODO 保存登录信息
            String s = JSONUtil.toJsonStr(apiResponse.getData());
            return JSONUtil.toBean(s, Oauth2TokenVo.class);
        }
        throw new ApiException(ResultCode.USER_ERROR_A0500);
    }

    /**
     * 根据账户查询用户信息
     *
     * @param username 账户
     * @return SysUser
     */
    @Override
    public Optional<SysUser> findUserByUsername(String username) {
        SysUser sysUser = getOne(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUsername, username));
        return Optional.ofNullable(sysUser).map(
                user -> {
                    List<SysRole> roles = roleService.queryUserRoleListByUid(user.getId());
                    user.setRoles(roles);
                    return user;
                }
        );
    }

    /**
     * 根据用户ID更新用户密码
     *
     * @param username    账户
     * @param newPassword 新密码
     */
    @Transactional
    @Override
    public void updateUserPasswordById(String username, String newPassword) {
        String pwd = passwordEncoder.encode(newPassword);
        update(new LambdaUpdateWrapper<SysUser>()
                .set(SysUser::getPassword, pwd)
                .eq(SysUser::getUsername, username)
        );
    }

}
